package code;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class YearMonthDayExtra {
	private static final int	MIN_YEAR	= 1990;
	private static final int	MAX_MONTH	= 12;
	private static final int	MAX_DAY		= 31;

	/**
	 * return the parsed value, else -1. Call this method if you do not want exceptions to be used to control the flow of logic just to
	 * parse a string into an integer.
	 * 
	 * @param text The text that contains a number.
	 * @return The integer or -1 if unsuccessful
	 */
	public static int tryParse(String text) {
		try {
			return Integer.parseInt(text);
		}
		catch (NumberFormatException e) {
			return -1;
		}
	}

	// Fields -----------------------------------------------------------------

	private int		year;
	private int		month;
	private int		day;
	private String	extra;

	// Constructors -----------------------------------------------------------

	public YearMonthDayExtra(int year, int month, int day, String extra) {
		this.year = year;
		this.month = month;
		this.day = day;
		this.extra = extra;
	}

	public YearMonthDayExtra(String text, DateFormat format) {
		splitText(text, format);
	}

	// Getters / Setters ------------------------------------------------------

	public int getDay() {
		return day;
	}

	public String getExtra() {
		return extra;
	}

	public int getMonth() {
		return month;
	}

	public int getYear() {
		return year;
	}

	/**
	 * Split the given text up into it's year, month, day and extra components. If things aren't going swimmingly, then set them to -1.
	 * 
	 * @return true if a successful value was obtained.
	 */
	public boolean splitText(String text, DateFormat format) {
		if (parseForYearMonthDate(text, format))
			return true;

		return false;
	}

	public boolean valid() {
		return !((getYear() == -1) || (getMonth() == -1) || (getDay() == -1));
	}

	/**
	 * Parse the given string for a valid value (-1 for invalid)
	 * 
	 * @param day input text
	 * @return The value. Returns -1 if not a valid month.
	 */
	private int parseDay(String day) {
		int val = tryParse(day);

		if (val <= 0 || val > MAX_DAY)
			val = -1;

		return val;
	}

	/**
	 * parse the given string for a specific format of year and month without any delimiters. If the numbers fit, are valid years, months,
	 * then set the year and month.
	 * 
	 * @param text
	 * @return returns true if the text given contains a valid year and month.
	 */
	private boolean parseForYearMonthDate(String text, DateFormat format) {
		if (format.matches(text)) {
			String delimeter = "-|_|( - )|( _ )|//";// DateFormat.extractDateDelimeter(name);

			Pattern pattern = Pattern.compile(delimeter);
			String[] dateMatches = pattern.split(text);

			if (format.getFormat() == "yyyyMM") {
				setYear(text.substring(0, 4));
				setMonth(text.substring(4, 6));
				return true;
			} else {
				setYear((dateMatches.length >= 1) ? parseYear(dateMatches[0]) : -1);
				setMonth((dateMatches.length >= 2) ? parseMonth(dateMatches[1]) : -1);
				setDay((dateMatches.length >= 3) ? parseMonth(dateMatches[2]) : -1);
				setExtra((dateMatches.length >= 4) ? dateMatches[3] : "");

				if (day == -1) {
					String remainingText = dateMatches[2];
					// sometimes there is no delimiter or anything before the description
					Pattern patternDay = Pattern.compile("\\d{1,2}");

					Matcher matchesDay = patternDay.matcher(remainingText);
					if (matchesDay.find()) {
						setDay(matchesDay.group());
						String extra = remainingText.substring(matchesDay.end());
						setExtra(extra);
					}
				}
			}
		}

		return valid();
	}

	/**
	 * Parse the given string for a valid value.
	 * 
	 * @param month input text
	 * @return The value. Returns -1 if not a valid month.
	 */
	private int parseMonth(String month) {
		int val = tryParse(month);

		if (val <= 0 || val > MAX_MONTH)
			val = -1;

		return val;
	}

	/**
	 * Parse the given string for a valid value.
	 * 
	 * @param year input text
	 * @return returns the value. Returns -1 if not a valid year.
	 */
	private int parseYear(String year) {
		int val = tryParse(year);

		if (val <= MIN_YEAR)
			val = -1;

		return val;
	}

	public void setDay(String day) {
		setDay(parseDay(day));
	}

	public void setDay(int day) {
		if (day > 0 && day <= MAX_DAY)
			this.day = day;
		else
			this.day = -1;
	}

	public void setMonth(String month) {
		setMonth(parseMonth(month));
	}

	public void setMonth(int month) {
		if (month > 0 && month <= MAX_MONTH)
			this.month = month;
		else
			this.month = -1;
	}

	public void setYear(String year) {
		setYear(parseYear(year));
	}

	public void setYear(int year) {
		if (year > MIN_YEAR)
			this.year = year;
		else
			this.year = -1;
	}

	public void setExtra(String extra) {
		this.extra = extra.trim();
	}
}
